﻿// ===============================================================================
// XCI.NET 西安交通信息WinForm开发框架 2018 版权所有
// ===============================================================================
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using XCI.Helper;

namespace XCI.Core
{
    /// <summary>
    /// 对象实例管理器
    /// </summary>
    public class BeanManager<T> where T : class
    {
        #region 私有变量

        private readonly ConcurrentDictionary<string, T> _instances = new ConcurrentDictionary<string, T>();
        private readonly Dictionary<string, Bean> _configs;

        #endregion

        #region 构造函数

        /// <summary>
        /// 初始化对象实例管理器新实例
        /// </summary>
        public BeanManager()
        {
            this._configs = new Dictionary<string, Bean>();
        }

        /// <summary>
        /// 初始化对象实例管理器新实例
        /// </summary>
        /// <param name="configs">使用配置信息初始化所有实例</param>
        public BeanManager(Dictionary<string, Bean> configs)
        {
            this._configs = configs ?? new Dictionary<string, Bean>();
            this.Init();
        }

        #endregion

        #region 公共方法

        /// <summary>
        /// 创建新实例
        /// </summary>
        /// <param name="name">配置名称</param>
        /// <returns>返回新实例</returns>
        public T Create(string name)
        {
            Guard.NotNull(name, nameof(name));
            if (_configs.TryGetValue(name, out var bean))
            {
                return Create(bean);
            }
            throw new ArgumentException("无效的组件名称", nameof(name));
        }

        /// <summary>
        /// 创建新实例
        /// </summary>
        /// <param name="bean">配置Bean</param>
        /// <returns>返回新实例</returns>
        public T Create(Bean bean)
        {
            Guard.NotNull(bean, nameof(bean));
            Guard.NotNullOrWhiteSpace(bean.Provider, nameof(bean.Provider));

            var instance = ObjectHelper.CreateInstance(bean.Provider, bean.Constructor);
            ObjectHelper.SetObjectValue(instance, bean.Property);
            return instance as T;
        }

        /// <summary>
        /// 是否存在指定名称的实例
        /// </summary>
        /// <param name="name">配置名称</param>
        /// <returns>存在返回<c>true</c>,否则返回<c>false</c></returns>
        public bool Exists(string name)
        {
            Guard.NotNull(name, nameof(name));
            return _instances.ContainsKey(name);
        }

        /// <summary>
        /// 获取指定名称的实例对象
        /// </summary>
        /// <param name="name">配置名称</param>
        /// <param name="defaultValueFactory">如果找不到,使用此回调函数</param>
        /// <returns>如果存在指定名称的实例直接返回,否则返回<paramref name="defaultValueFactory"/>的值</returns>
        public T TryGet(string name, Func<T> defaultValueFactory = null)
        {
            Guard.NotNull(name, nameof(name));
            if (_instances.TryGetValue(name, out var v))
            {
                return v;
            }
            return defaultValueFactory?.Invoke();
        }

        /// <summary>
        /// 获取指定名称的实例对象,如果没有找到,使用指定的回调函数的值返回并添加到实例容器中
        /// </summary>
        /// <param name="name">配置名称</param>
        /// <param name="defaultValueFactory">如果找不到,使用此回调函数</param>
        /// <returns>如果存在指定名称的实例直接返回,否则返回<paramref name="defaultValueFactory"/>的值返回,并添加到实例容器中</returns>
        public T TryGetOrAdd(string name, Func<T> defaultValueFactory = null)
        {
            Guard.NotNull(name, nameof(name));
            if (_instances.TryGetValue(name, out var v))
            {
                return v;
            }
            if (defaultValueFactory != null)
            {
                var nv = defaultValueFactory();
                _instances.TryAdd(name, nv);
                return nv;
            }
            return default(T);
        }

        /// <summary>
        /// 获取所有实例名称
        /// </summary>
        public string[] GetKeys()
        {
            return _instances.Keys.ToArray();
        }

        /// <summary>
        /// 获取所有实例对象
        /// </summary>
        public T[] GetValues()
        {
            return _instances.Values.ToArray();
        }

        /// <summary>
        /// 添加指定名称的实例到实例容器中
        /// </summary>
        /// <param name="name">配置名称</param>
        /// <param name="provider">实例对象</param>
        /// <returns>添加成功<c>true</c>,否则返回<c>false</c></returns>
        public bool Add(string name, T provider)
        {
            Guard.NotNull(name, nameof(name));
            return _instances.TryAdd(name, provider);
        }

        /// <summary>
        /// 添加指定名称的实例到实例容器中,如果存在则更新.
        /// </summary>
        /// <param name="name">配置名称</param>
        /// <param name="provider">实例对象</param>
        public void AddOrUpdate(string name, T provider)
        {
            Guard.NotNull(name, nameof(name));
            _instances.AddOrUpdate(name, provider, (k, v) => provider);
        }

        /// <summary>
        /// 移除指定名称的实例
        /// </summary>
        /// <param name="name">配置名称</param>
        /// <returns>移除成功返回<c>true</c>,否则返回<c>false</c></returns>
        public bool Remove(string name)
        {
            Guard.NotNull(name, nameof(name));
            return _instances.TryRemove(name, out var v);
        }

        /// <summary>
        /// 清空所有实例
        /// </summary>
        public void Clear()
        {
            _instances.Clear();
        }

        #endregion

        #region 私有方法

        /// <summary>
        /// 读取配置信息创建所有实例
        /// </summary>
        private void Init()
        {
            foreach (var config in _configs)
            {
                var instance = Create(config.Value);
                _instances.AddOrUpdate(config.Key, instance, (k, v) => instance);
            }
        }

        #endregion
    }
}